import {io, Socket} from "socket.io-client";
interface SocketMap {
    channels: Map<string, any>|any;
    headers?: any;
    host?: string;
}
const socket:SocketMap = {
    channels: {},
    headers: {},
    host: import.meta.env['VITE_SOCKET_IO_GATEWAY']??''
};

const socketHeader = (key: string, value: any) =>{
    socket.headers[key] = value;
}

const socketHost = (host: string) => {
    socket.host = host;
}
const socketIO = (headers:any = {}, host: string = '') => {
    return channel('', host, headers);
}

const  channel = ( ch: string = '' , headers:any = {}, host: string = '') => {
    host = host === '' ? (socket.host??'') : host;
    const hostEndIndex: number = host.length - 1;
    host = host.charAt(hostEndIndex) === '/' ? host.substring(0, hostEndIndex) : host;
    ch = ch.charAt(0) === '/' ? ch.substring(1, ch.length) : ch;
    const url: string = host + '/' + ch;
    if (socket.channels[url]){
        return  socket.channels[url];
    }
    headers = {...socket.headers, ...headers};
    const client = io(url, {
        extraHeaders: headers
    });
    socket.channels[url] = client;
    return socket.channels[url];
}
const socketListener = (event: string, ch: string = '', host: string = '', headers: any = {}) => {
    const client: Socket = channel(ch, headers, host);
    return (cb: Function) => {
        client.on(event, (data) => {
            cb(data, client, ch);
        });
    }
}
const  onConnected = (cb:Function, ch: string = '', host: string='', headers: any = {}) =>{
    const listeners:any = {
    };
    socketListener('connect', ch, host, headers)((data: any, socket: any, ch: string) => {
        for (const event in listeners) {
            let listener = listeners[event];
            socketListener(event, ch, host, headers)(listener);
            delete listeners[event];
        }
        cb(data, socket, ch);
    });
    const listener =  (listener:Function, event: string) => {
        listeners[event] = listener;
        return listener;
    }

    return listener;
}

export {onConnected, socketIO, channel, socketHost, socketHeader, socketListener}